#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <WiFi.h>
#include <WebServer.h>
#include <SPIFFS.h> //闪存文件系统
#include <Arduino.h>
// #include <PubSubClient.h>
#include <HTTPClient.h>
// #define MQTT_MAX_PACKET_SIZE 512
// #define MQTT_KEEPALIVE 300
#include <ArduinoJson.h>
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels

#define ALCOHOL 35
#define LED2 2

// #define TARGETIP targetip.c_str()
// #define TARGETPORT targetport.c_str()

WebServer server(80); //创建Web服务端口为80
void wificonfig();
void removeConfig();
void get_sensor_data();
void serializeJson_data();
void sendsensordata();
void printLocalTime();
const char *ntpServer = "pool.ntp.org";
const long gmtOffset_sec = 8 * 3600;
const int daylightOffset_sec = 0;

// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
// The pins for I2C are defined by the Wire-library.
// On an arduino UNO:       A4(SDA), A5(SCL)
// On an arduino MEGA 2560: 20(SDA), 21(SCL)
// On an arduino LEONARDO:   2(SDA),  3(SCL), ...
#define OLED_RESET -1       // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// HardwareSerial MySerial(1);

String timestamp, temperature1, temperature2, alcohol, heartRate, SOP2, hPress, lPress;
const char read_t_command[3] = {0xA5, 0x15, 0xBA};
char read_heart_command = 0x8A;

WiFiClient client;
String targetip;
String targetport;
String heart_str;
String t_str;
String sensor_data_json;
String str1;
bool get_h_data_finish = false;
bool get_t_data_finish = false;
bool get_sensor_data_finish = false;
void setup()
{
    pinMode(32, INPUT_PULLDOWN);
    Serial.begin(115200);
    Serial1.begin(38400, SERIAL_8N1, 25, 26);
    Serial2.begin(115200);
    // Serial1.begin(115200);
    pinMode(LED2, OUTPUT);
    // pinMode(ALCOHOL,ANALOG);
    digitalWrite(LED2, HIGH);
    delay(1000);
    // File co = SPIFFS.open("/config.json", "r");
    // Serial.println(co);
    if (digitalRead(32) == 1)
    { //按键扫描
        delay(3000);
        if (digitalRead(32) == 1)
        {
            removeConfig();
            digitalWrite(LED2, LOW);
        }
    }

    // pinMode(ALCOHOL, INPUT);
    // adcAttachPin(ALCOHOL); //将引脚连接到ADC
    // // adcStart(ALCOHOL);//在连接的引脚总线上开始ADC转换
    // analogReadResolution(16); //设置aliogRead返回值的分辨率
    // if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS))
    // {
    //     Serial.println(F("SSD1306 allocation failed"));
    //     for (;;)
    //         ; // Don't proceed, loop forever
    // }
    wificonfig();
    delay(1000);
    configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
    delay(100);
    while (!client.connect(targetip.c_str(), atoi(targetport.c_str())))
    {
        Serial.print("-");
        delay(500);
        if (digitalRead(32) == 1)
        { //按键扫描
            delay(3000);
            if (digitalRead(32) == 1)
            {
                removeConfig();
                digitalWrite(LED2, LOW);
            }
        }
    }
    Serial.println("\r\nSucess : ");
    String temp = "ESP32 First Data!";
    client.println(temp);
    // Clear the buffer
    // display.clearDisplay();
    // display.display();
    Serial1.print(read_heart_command); //
}

void loop()
{
    // printLocalTime();
    get_sensor_data();
    if (get_sensor_data_finish)
    {
        serializeJson_data();
        sendsensordata();
        get_sensor_data_finish = false;
        get_t_data_finish = false;
        get_h_data_finish = false;
    }
    int len = client.available();
    // Serial.println("avab:" + String(len));
    if (len > 0)
    {
        int j;
        for (j = 0; j < len; j++)
        {
            str1[j] = client.read();
        }
        str1[j] = '\0';
        Serial.print("Rec:");
        Serial.println(str1);
    }
    delay(100);
    if (digitalRead(32) == 1)
    {
        removeConfig();
    }
}

void sendsensordata()
{
    if (client.connected())
    {
        client.println(sensor_data_json);
    }
    else
    {
        while (!client.connect(targetip.c_str(), atoi(targetport.c_str())))
        {
            Serial.println("connect lost,retry!");
            delay(100);
        }
        client.println(sensor_data_json);
    }
}

void serializeJson_data()
{
    // String timestamp, temperature1, temperature2, alcohol, heartRate, SOP2, hPress, lPress;
    DynamicJsonDocument sensor_data_doc(1024);
    sensor_data_doc["deviceType"] = "watch";
    sensor_data_doc["deviceID"] = WiFi.macAddress();
    sensor_data_doc["timestamp"] = timestamp;
    sensor_data_doc["temperature1"] = temperature1;
    sensor_data_doc["temperature2"] = temperature2;
    sensor_data_doc["heartRate"] = heartRate;
    sensor_data_doc["SOP2"] = SOP2;
    sensor_data_doc["hPress"] = hPress;
    sensor_data_doc["lPress"] = lPress;
    sensor_data_json = "";
    serializeJson(sensor_data_doc, sensor_data_json);
    Serial.println(sensor_data_json);
}

void get_sensor_data()
{
    //获取时间
    struct tm timeinfo;
    getLocalTime(&timeinfo);
    char buf[64];
    strftime(buf, 64, "%A, %B %d %Y %H:%M:%S", &timeinfo);
    timestamp = String(buf);
    if (Serial1.available())
    {
        delay(10);
        heart_str = Serial1.readString();
        // Serial.println(heart_str);
        Serial.println("read h");
        get_t_data_finish = true;
        // String timestamp, temperature1, temperature2, alcohol, heartRate, SOP2, hPress, lPress;
        heartRate = String(heart_str[65] * 1);
        SOP2 = String(heart_str[66] * 1);
        hPress = String(heart_str[71] * 1);
        lPress = String(heart_str[72] * 1);
    }
    Serial2.print(read_t_command);
    while (!Serial2.available())
    {
        Serial.println("wait t");
        delay(10);
    }
    delay(10);
    t_str = Serial2.readString();
    get_h_data_finish = true;
    temperature1 = String((t_str[4] * 255 + t_str[5]) / 100.0);
    temperature2 = String((t_str[6] * 255 + t_str[7]) / 100.0);
    // alcohol = String(analogRead(ALCOHOL) * 1);
    Serial.println(alcohol);
    // alcohol = String(30);
    // Serial.println(t_str);
    get_sensor_data_finish = get_h_data_finish & get_t_data_finish;
}

void printLocalTime()
{
    struct tm timeinfo;
    if (!getLocalTime(&timeinfo))
    {
        Serial.println("Failed to obtain time");
        return;
    }
    Serial.print("Now Time :");
    Serial.println(&timeinfo, "%A, %B %d %Y %H:%M:%S");
    // char buf[64];
    // strftime(buf, 64, "%A, %B %d %Y %H:%M:%S", &timeinfo);
    // timestamp = String(buf);
    // timestamp = String(timeinfo.tm_year) + "-" +String(timeinfo.tm_mon)+ "-" +String(timeinfo.tm_mday)+ "-" \
    // +String(timeinfo.tm_hour)+ "-" +String(timeinfo.tm_min)+ "-" +String(timeinfo.tm_sec);
    // Serial.println(timestamp);
    // Serial.println("###");
}

void handleRoot()
{ //展示网页的关键代码
    // Serial.println("handleroot");
    if (SPIFFS.exists("/index.html"))
    {

        // Serial.println("exists");
        File index = SPIFFS.open("/index.html", "r");
        server.streamFile(index, "text/html");
        index.close();
    }
}

void handleConnect()
{                                     //处理配置信息的函数
    String ssid = server.arg("ssid"); // arg是获取请求参数，视频中最后面展示了请求的完整链接
    String password = server.arg("password");
    targetip = server.arg("targetip");
    targetport = server.arg("targetport");
    server.send(200, "text/plain", "OK");
    WiFi.mode(WIFI_STA);                        //改变wifi模式
    WiFi.begin(ssid.c_str(), password.c_str()); // String类型直接用会报错，不要问为什么，转成char *就行了。
    removeConfig();                             // 不管有没有配置先删除一次再说。
    String payload;                             // 拼接构造一段字符串形式的json数据长{"ssid":"xxxxx","password":"xxxxxxxxxxx"}
    payload += "{\"ssid\":\"";
    payload += ssid;
    payload += "\",\"password\":\"";
    payload += password;
    payload += "\",\"targetip\":\"";
    payload += targetip;
    payload += "\",\"targetport\":\"";
    payload += targetport;
    payload += "\"}";
    File wifiConfig = SPIFFS.open("/config.json", "w");
    wifiConfig.println(payload); //将数据写入config.json文件中
    wifiConfig.close();
    delay(100);
    while (WiFi.status() != WL_CONNECTED)
    {
        delay(200);
        Serial.print(".");
    }
    Serial.println();
    Serial.println(WiFi.localIP());
}

void removeConfig()
{
    Serial.println("Deleting old configuration");
    if (SPIFFS.exists("/config.json"))
    { // 判断有没有config.json这个文件
        if (SPIFFS.remove("/config.json"))
        {
            Serial.println("Old configuration deleted successfully");
        }
        else
        {
            Serial.println("Failed to delete old configuration");
        }
    }
}
void wificonfig()
{
    if (SPIFFS.begin())
    { // 打开闪存文件系统，记得在你连接板子下载的过程中选Flash Size的时候不要选no SPIFFS,你可以选1M、2M、3M都无所谓，因为两个文件都很小
        Serial.println("Flash file system opened successfully");
        //    SPIFFS.format();
    }
    else
    {
        Serial.println("Flash file system open failed");
    }
    if (SPIFFS.exists("/config.json"))
    { // 判断有没有config.json这个文件
        Serial.println("Configuration information exists, connecting automatically");
        delay(10);
        const size_t capacity = JSON_OBJECT_SIZE(1) + JSON_OBJECT_SIZE(2) +
                                JSON_OBJECT_SIZE(1) + JSON_OBJECT_SIZE(2) + 60; //分配一个内存空间
        DynamicJsonDocument doc(capacity);                                      // 声明json处理对象
        File configJson = SPIFFS.open("/config.json", "r");
        // Serial.println("read file success");
        deserializeJson(doc, configJson); // json数据序列化

        const char *ssid = doc["ssid"];
        const char *password = doc["password"];
        const char *tip = doc["targetip"];
        const char *tport = doc["targetport"];

        targetip = String(tip);

        targetport = String(tport);
        configJson.close();
        WiFi.mode(WIFI_STA);        // 更换wifi模式
        WiFi.setSleep(false);       //关闭STA模式下wifi休眠，提高响应速度
        WiFi.begin(ssid, password); // 连接wifi
        int i = 0;
        Serial.println("WiFi Connecting ");
        while (WiFi.status() != WL_CONNECTED)
        {
            delay(500);
            Serial.println(".");
            i++;
            if (i > 30)
            {
                removeConfig();
            }
            if (digitalRead(32) == 1)
            {
                delay(1000);
                if (digitalRead(32) == 1)
                    removeConfig();
            }
        }
        Serial.print("localIP:");
        Serial.println(WiFi.localIP());
    }
    else
    {
        Serial.println("There is no configuration information, opening web distribution mode");
        IPAddress softLocal(192, 168, 1, 1);
        IPAddress softGateway(192, 168, 1, 1);
        IPAddress softSubnet(255, 255, 255, 0);
        WiFi.softAPConfig(softLocal, softGateway, softSubnet);
        WiFi.softAP("esp32", "12345678"); //这里是配网模式下热点的名字和密码
        Serial.println(WiFi.softAPIP());
    }
    server.on("/", handleRoot);       // web首页监听
    server.on("/set", handleConnect); // 配置ssid密码监听
    server.begin();
    while (WiFi.status() != WL_CONNECTED)
    {
        server.handleClient();
    }
    server.close();
}
